package org.budo.jdbc.dao.resultset.handler;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;

import org.budo.jdbc.dao.ResultSetHandler;
import org.budo.support.javax.sql.util.ResultSetUtil;
import org.budo.support.lang.util.ReflectUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 * 
 * @see org.budo.jdbc.dao.resultset.handler.AnnotationEntityListResultSetHandler
 */
@Slf4j
public class AnnotationEntityResultSetHandler<T> implements ResultSetHandler<T> {
    private String[] _columnLabels;

    private Class<T> _entityType;

    public AnnotationEntityResultSetHandler(Class<T> entityType) {
        this._entityType = entityType;
    }

    @Override
    public T handleResultSet(ResultSet resultSet) {
        if (null == resultSet)        {
            return null;
        }

        if (ResultSetUtil.next(resultSet)) {
            return this.handleResultSetLine(resultSet);
        }

        return null;
    }

    private synchronized String[] _getColumnLabels(ResultSet resultSet) {
        if (null == this._columnLabels) {
            this._columnLabels = ResultSetUtil.getColumnLabels(resultSet);
        }

        return this._columnLabels;
    }

    private T handleResultSetLine(ResultSet resultSet) {
        if (null == resultSet) {
            return null;
        }

        String[] columnLabels = this._getColumnLabels(resultSet);

        Object newInstance = ReflectUtil.newInstance(this._entityType);
        Map<String, Object> valueMap = ResultSetUtil.toMap(resultSet, columnLabels);
        this._setFieldValues(valueMap, newInstance);

        return (T) newInstance;
    }

    private void _setFieldValues(Map<String, Object> valueMap, Object newInstance) {
        for (String columnLabel : _columnLabels) {
            Field field = this._columnLabelToField(columnLabel);
            if (null == field) {
                log.info("#56 field not found, entityType=" + this._entityType + ", columnLabel=" + columnLabel);
                continue;
            }

            Object value = valueMap.get(columnLabel);
            Object fieldValue = this.fieldValueTypeConvert(value, field.getType()); // 属性值类型处理
            ReflectUtil.setFieldValue(newInstance, field, fieldValue);
        }
    }

    private Field _columnLabelToField(String columnLabel) {
        List<Field> fields = ReflectUtil.getAllFields(this._entityType);
        for (Field field : fields) {
            if (field.getName().equalsIgnoreCase(columnLabel)) {
                return field;
            }

            Column annotation = field.getAnnotation(Column.class);
            if (null != annotation //
                    && columnLabel.equalsIgnoreCase(annotation.name())) { // TODO `` 问题
                return field;
            }
        }

        return null;
    }

    protected Object fieldValueTypeConvert(Object value, Class<?> type) {
        if (null == value) {
            return value;
        }

        // 类型匹配
        if (type.isAssignableFrom(value.getClass())) {
            return value;
        }

        throw new UnsupportedOperationException("#78 this=" + this + ", 未实现 从 " + value.getClass() + " 到 " + type + " 的类型转换");
    }
}